﻿
import com.kirillam.handy.core.HATObject;

import com.kirillam.handy.util.ClassUtil;

import com.kirillam.handy.log.LogWriter;
import com.kirillam.handy.log.TraceWriter;

/**
* Static logging class to perform global logging functions.
* 
* @author Kirill Mourzenko
*/

class com.kirillam.handy.log.HATLogger
{
	// CONSTANTS
	
	public	static var LEVEL_INFO	: String	= "INFO";
	public	static var LEVEL_DEBUG	: String	= "DEBUG";
	public	static var LEVEL_WARN	: String	= "WARNING";
	public	static var LEVEL_ERROR	: String	= "ERROR";
	public	static var LEVEL_SEVERE	: String	= "SEVERE";		// ALWAYS GETS LOGGED
	
	public	static var LEVEL_ALL	: Array		= [ LEVEL_INFO, LEVEL_DEBUG, LEVEL_WARN, LEVEL_ERROR, LEVEL_SEVERE ];
	
	
	// DATASTRUCTURES
	
	private static var logLevels	: Object	= new Object();
	private static var logClasses	: Object	= new Object();
	
	
	// OBJECTS
	
	private static var writer		: LogWriter;
	private static var instance		: HATLogger	= new HATLogger();	// USED AS STATIC INITIALIZATION.
	
	
	
	/** 
	 * Defines the logging levels of messages that will be logged.
	 * 
	 * @param	...		Any number of arguments consisting of LEVEL_INFO, LEVEL_DEBUG, LEVEL_WARN, LEVEL_ERROR, LEVEL_ALL.
	 * 					LEVEL_SEVERE gets logged even if it's not specified in here or it's sent from a class that wasn't
	 * 					listed with logged classes.
	 */
	
	public	static function setLogLevels()
	{
		logLevels								= new Object();
		
		if ( arguments[ 0 ] instanceof Array ) {
			arguments							= arguments[ 0 ];
		}
		
		for ( var i : String in arguments ) {
			logLevels[ arguments[ i ] + "L" ]	= true;
		}
	}
	
	
	/**
	 * Defines the classes that log messages should be printed for.
	 * 
	 * @param	...		Any number of arguments that are package paths to classes. Paths don't have to be complete.
	 * 					An incomplete path will have logs messages printed for all classes in the package and any
	 * 					packages inside it. Use * to terminate an incomplete path, eg to print for com.kirillam.handy.log.HATLogger
	 * 					and com.kirillam.handy.core.HATObject pass in "com.kirillam.handy.*". To print for any package
	 * 					and any class pass in "*".
	 */
	
	public static function setLogClasses()
	{
		logClasses	= new Object();
		
		for ( var i : String in arguments ) {
			logClasses[ arguments[ i ] ]	= true;
		}
	}
	
	
	
	/**
	 * Sets the output destination to write to.
	 * 
	 * @param	w	Writer.
	 */
	
	public	static function setWriter( w : LogWriter )
	{
		writer	= w;
	}
	
	
	/**
	 * Logs a message writing to the writer that is set or if there isn't one then to the standard trace output.
	 * 
	 * @param	level		Log level.
	 * @param	className	Class path of the object logging the message.
	 * @param	method		Method from which the message was logged.
	 * @param	msg			Log message.
	 */
	
	public	static function writeLog( level : String, className : String, method : String, msg : Object )
	{
		if ( level != LEVEL_SEVERE ) {
			
			if ( !logLevels[ level + "L" ] ) return;
		
			if ( !logClasses[ "*" ] ) {
				
				var classPath	: String	= "";
				var path		: Array		= className.split( "." );
				for ( var i : Number = 0; i < path.length; i++ ) {
					
					classPath				+= path[ i ];
					if ( path.length == i + 1 ) {
						
						if ( !logClasses[ classPath ] ) return;
						break;
					}
					
					classPath				+= ".";
					if ( logClasses[ classPath + "*" ] ) break;
				}
			}
		}
		
		
		if ( writer == null ) {
			writer							= new TraceWriter();
		}
		writer.write( level, className, method, msg );
	}
	
	
	/**
	 * Logs a message with an info level.
	 * 
	 * @param	className	Class path of the object logging the message.
	 * @param	method		Method from which the message was logged.
	 * @param	msg			Log message.
	 */
	
	public	static function INFO( className : String, method : String, msg : Object )
	{
		writeLog( LEVEL_INFO, className, method, msg );
	}
	
	
	/**
	 * Logs a message with a debug level.
	 * 
	 * @param	className	Class path of the object logging the message.
	 * @param	method		Method from which the message was logged.
	 * @param	msg			Log message.
	 */
	
	public	static function DEBUG( className : String, method : String, msg : Object )
	{
		writeLog( LEVEL_DEBUG, className, method, msg );
	}
	
	
	/**
	 * Logs a message with a warn level.
	 * 
	 * @param	className	Class path of the object logging the message.
	 * @param	method		Method from which the message was logged.
	 * @param	msg			Log message.
	 */
	
	public	static function WARN( className : String, method : String, msg : Object )
	{
		writeLog( LEVEL_WARN, className, method, msg );
	}
	
	
	/**
	 * Logs a message with an error level.
	 * 
	 * @param	className	Class path of the object logging the message.
	 * @param	method		Method from which the message was logged.
	 * @param	msg			Log message.
	 */
	
	public	static function ERROR( className : String, method : String, msg : Object )
	{
		writeLog( LEVEL_ERROR, className, method, msg );
	}
	
	
	/**
	 * Logs a message with a severe level.
	 * 
	 * @param	className	Class path of the object logging the message.
	 * @param	method		Method from which the message was logged.
	 * @param	msg			Log message.
	 */
	
	public	static function SEVERE( className : String, method : String, msg : Object )
	{
		writeLog( LEVEL_SEVERE, className, method, msg );
	}
	
	
	
	
	/** 
	 * Only a single instance is allowed to be created because this class is not meant for instanciation.
	 * The single instance is used for static initialization.
	 */
	
	function HATLogger()
	{
		if ( instance != null ) {
			HATLogger.SEVERE( ClassUtil.getClassPath( this ), ClassUtil.getMethodName( this, arguments.callee ), "Attempting to instanciate a static class." );
			throw new Error( "Attempting to instanciate a static class com.kirillam.handy.log.HATLogger" );
		}
		
		instance					= this;
		// 	CREATE METHODS ON ALL OBJECTS TO ALLOW THEM TO DO LOGGING.
			
		Object.prototype.INFO		=  function( message : Object )
		{
			var m	: String		= ClassUtil.getMethodName( this, arguments.caller );
			HATLogger.INFO( ClassUtil.getClassPath( this ), m ? m : "nameless", message );
		}
			
			
		Object.prototype.DEBUG		=  function( message : Object )
		{
			var m	: String		= ClassUtil.getMethodName( this, arguments.caller );
			HATLogger.DEBUG( ClassUtil.getClassPath( this ), m ? m : "nameless", message );
		}
			
			
		Object.prototype.WARN		=  function( message : Object )
		{
			var m	: String		= ClassUtil.getMethodName( this, arguments.caller );
			HATLogger.WARN( ClassUtil.getClassPath( this ), m ? m : "nameless", message );
		}
			
			
		Object.prototype.ERROR		=  function( message : Object )
		{
			var m	: String		= ClassUtil.getMethodName( this, arguments.caller );
			HATLogger.ERROR( ClassUtil.getClassPath( this ), m ? m : "nameless", message );
		}
			
		Object.prototype.SEVERE		=  function( message : Object )
		{
			var m	: String		= ClassUtil.getMethodName( this, arguments.caller );
			HATLogger.SEVERE( ClassUtil.getClassPath( this ), m ? m : "nameless", message );
		}
		
		
		_global.ASSetPropFlags( Object.prototype, "INFO", 	7, true );
		_global.ASSetPropFlags( Object.prototype, "DEBUG", 	7, true );
		_global.ASSetPropFlags( Object.prototype, "WARN", 	7, true );
		_global.ASSetPropFlags( Object.prototype, "ERROR", 	7, true );
		_global.ASSetPropFlags( Object.prototype, "SEVERE", 7, true );
	}
}